@							SRLOS source code
@						SRLOS Team All Rights Reserved!
@@filename	kernel_asm_fiq.s
@@author	boceanc.
@@date		2010/04/17
@@comment	this file is a asm file.It is used to handle FIQ interrupts.
@			It supports nestable interrupt.In system all Mode of arm use
@			ARM 32 bits instruction.
@@note		more information see <interrupt desgin> doc.
@@WARNING	In FIQ mode, we will don't enable any interrupts,so this must be finshed fastly and no interrupted!
@@WARNING	In this mode, INT handle program must be no parameters!

.section .text

.global			g_interrupt_fiq				@	export lable for linking
.extern			g_p_cur_thread			@	import courrent task for using

@0x10		EQU				0x10		@	define user mode type micro
@0x1F		EQU				0x1F		@	define system mode type micro

.arm    									@	use 32 bits instruction
g_interrupt_fiq:
            	MSR CPSR_c,  #0xD1			@	disable fiq----- 110 10001
				MRS	R13, SPSR		        @	geting interrupted mode type
				AND	R13, R13, #0x1F	        @	get mode type bits (low 5 bits)
				CMP R13, #0x10		        @	test whether user mode type
				BEQ l_fiq_usrmode				@	jump to user mode type processing
				CMP R13, #0x1F		        @	test whether system mode type
				BEQ l_fiq_sysmode				@	jump to system mode type processing
@				BEQ	l_error					@	the interrupted mode is not corrected
											@	we should shut down system or reset!


@system mode type process
l_fiq_sysmode:
        		MOV	R13,R0				@	save r0, we use r0 get sp in syste mode
				MSR CPSR_c, #0xDF			@	change to sysem mode type
				MOV R0, R13					@	get STACK from system mode type
				MSR CPSR_c, #0xD1			@	change back to IRQ mode type
@now, we should exchange R0 and R13, inorder to make R13 pointer to the
@correct stack pointer--sp@here we use three times bit "OR" operaton^_^!(thanks hongwei.sun)
				EOR R0,R0, R13			@	a = a ^ b
				EOR R13, R0,R13		@   b = a ^ b
				EOR R0,R0, R13			@   a = a ^ b
				B l_fiq_proc_start				@	jump to handling start!

@user mode type process
l_fiq_usrmode:
        		EOR	R13, R13, R13	@
				LDR	R13, =g_p_cur_thread	@
				LDR R13, [R13]
				LDR R13, [R13]
@ok.now we have a useful stack for current mode type . run step 2: calculate R14(lr) and save it!
@current mode is IRQ. we calculate R14 to R14-4@ see other releation docs!
l_fiq_proc_start:
            	SUB R14, R14, #4	@	sub r14 to r14-4

				STMFD R13!, {R14}	@	push R14
				MRS R14, SPSR		@   we will never use R14 before resume context!
											@	so we can use it here!
				STMFD R13!, {R14}	@	push spsr

@now, step 3. save context
				STMFD R13!, {R0-R12}	@

@step 4. use r0 to save sp!
				MOV R0, R13				@	use r0 to save sp

@step 5. change mode type.
				MSR CPSR_c, #0xDF			@	change to sysem mode type


@step 6. save r13 of system mode type , using r2.
@(r2, we have saved.we just have one popurse to save lr and sp in system mode type)
				MOV R2, R13					@	save r13 to r2
				MOV R13, R0					@	use stack passed by r0

@step 8. save r13 and lr belonging to system mode type!
				STMFD R13!, {R2}			@	the r13 belonging to system mode type has saved in r2 before!
				STMFD R13!, {R14}			@	we never change R14 belonging to system mode type before,we can
											@	save it directly.


@now, we have saved all the registers!we can enable interrupt again now!
@step 9. Enable interrupt.including IRQ and FIQ.
@(we need not)	MSR CPSR_c, #0x1F			@	enable interrupt ------ 00 0 11111(carefor we must in SYS MODE)

@ok.step 10. now we can call interrupt handle to process
@------------------- handle start ------------------------



@------------------- handle end --------------------------

@now, we need to restore context.
@step 11.Disable interrupt including IRQ and FIQ.
@(we need not)	MSR CPSR_c, #0xDF			@	disable interrupt in system mode type(be carefor, now we are in SYS MODE!)

@now ,step 12. pop up r14
				LDMFD R13!, {R14}			@	ACPS, R13(or R13_<mode>) is always SP!

@step 13. use R0 to save R13.because current R13 is IRQ mode's.
				LDMFD R13!, {R0}			@	save R13 last mode

@step 14. now we will back to irq mode.so we have to save sp_fiq.
@when we change to IRQ mode , we can find it.Using R2!
				MOV R2, R13					@	R2 <= R13

@step 15. now we can restore (system mode / user mode)'s R13
				MOV R13, R0					@	we have stored it in R0 before

@step 16. we have to change to Interrupt mode to restore athor registers.
				MSR CPSR_c, #0xD1			@	110 10001

@step 17. now we break into Interrupt mode. So, we have to give the right stack SP!
				MOV R13, R2				@	we have stored it in R2 before.

@step 18. now we can restore the context
				LDMFD R13!, {R0-R12}	@	restore R0 - R12

@step 19. now we must restore SPSR. NOTE: here will not change the disable interrupt mode, because it's SPSR
@NOT CPSR!now, we have pass value by R14.er....ARM.
				LDMFD R13!, {R14}	@	restore SPSR to R14
				MSR SPSR, R14		@	restore SPSR.
									@	#########Here Will Not Occur Interrupt, Because This is SPSR, NOT CPSR!!!!
									@	CRSP still Disable Enterrupt!!#########
@step 20. now we can jump back to previous.
				LDMFD R13!,{R15}^		@	quit interrupt program
